﻿#include "graphPhasor.h"
#include <QPainter>


GraphPhasor::GraphPhasor(QWidget *parent) :
    QWidget(parent)
{
    phasor.Connect=0;
}
void GraphPhasor::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);

    phasor.Background=0;
    phasor.BkColor=WHITE;
    phasor.FrameColor=BLACK;
    phasor.PosX=this->width()/2;
    phasor.PosY=this->height()/2;

    int r=phasor.PosX;
    if(r>phasor.PosY)
        r=phasor.PosY;
    phasor.Radius=r-20;

    PhasorDraw(&phasor,&painter);
    painter.end();
}


/**********************************************************************************************************************
*  短箭头模型   电流使用
**********************************************************************************************************************/

static	GUI_POINT	ArrowModel[]={
    {0,0},
    {-2,0},
    {-2,-41},
    {-8,-41},
    {0,-52},
    {7,-41},
    {1,-41},
    {2,0},
};

/**********************************************************************************************************************
*   长箭头模型  电压使用
**********************************************************************************************************************/

static	GUI_POINT	LongArrowModel[]={
    {0,0},
    {-2,0},
    {-2,-64},
    {-6,-64},
    {0,-75},
    {5,-64},
    {1,-64},
    {2,0},
};

static	GUI_POINT	MidArrowModel[]={
    {0,0},
    {-2,0},
    {-2,-53},
    {-6,-53},
    {0,-64},
    {5,-53},
    {1,-53},
    {2,0},
};


/**********************************************************************************************************************
*   3线相量箭头定义
**********************************************************************************************************************/

static  PHASOR_ARROW    PhasorArrow3P[]={
    {0,YELLOW,0,LongArrowModel    ,"Ua"},     //Ua
    {0,GREEN, 0,LongArrowModel    ,"Ub"},     //Ub
    {0,RED  , 0,LongArrowModel    ,"Uc"},     //Uc
    {0,YELLOW,0,ArrowModel,"Ia"},             //Ia
    {0,YELLOW, 0,MidArrowModel,"Uab"},           //Uab
    {0,RED   , 0,ArrowModel,"Ic"},            //Ic
    {0,RED,  0,MidArrowModel,"Ucb"},             //Ucb
};


/**********************************************************************************************************************
*   4线相量箭头定义
**********************************************************************************************************************/

static  PHASOR_ARROW    PhasorArrow4P[]={
    {0,YELLOW,0,LongArrowModel,"Ua"},     //Ua
    {0,GREEN,0,LongArrowModel,"Ub"},     //Ub
    {0,RED,0,LongArrowModel,"Uc"},     //Uc
    {0,YELLOW,0,ArrowModel,"Ia"},             //Ia
    {0,GREEN,0,ArrowModel,"Ib"},             //Ib
    {0,RED,0,ArrowModel,"Ic"},             //Ic
};

/**********************************************************************************************************************
*   单线相量箭头定义
**********************************************************************************************************************/

static  PHASOR_ARROW    PhasorArrow1P[]={
    {0,OLIVE,0,LongArrowModel,"Ua"},     //Ua
    {0,OLIVE,0,ArrowModel,"Ia"},             //Ia
};


/**********************************************************************************************************************
*   箭头指针数组 第0,2项无意义 第1,3,4项分别对应单线 3线 4线
**********************************************************************************************************************/

static  PHASOR_ARROW*   PhasorArrowSet[]={
    NULL,PhasorArrow1P,NULL,
    PhasorArrow3P,PhasorArrow4P,
};


/**********************************************************************************************************************
*   变换方向后的箭头
**********************************************************************************************************************/
static	GUI_POINT	DeltaT[8];

float d2f(unsigned long ux[2])
{
    long a,b,uf;

    uf = 0;
    uf = ux[1]&0x80000000;

    a = (ux[1]&0x7ff00000)>>20;
    b = ux[1]&0xfffff;
    a-=1024 - 128;

    uf |=a<<23;
    uf |=b<<3;
    uf |=ux[0]>>29;

    return( *(float*)&uf );

}

/**********************************************************************************************************************
*   函数名: GetAngle
*   建立者: 王昊
* 建立日期: 2009.02.18
* 修改日期: 2009.02.18
*     参数:
*           tb: PHASOR指针 指向需要处理的PHASOR结构数据
*   返回值: 无
* 功能介绍:
*           读取PHASOR结构中的角度数据 供变换
**********************************************************************************************************************/

static  void    GetAngle(PHASOR*	pData)
{
    int *p;
    int i;

    //4线
    p = (int*)&(pData->P4Angle);
    for(i = 0 ;i < 6; i++)
        PhasorArrow4P[i].Angle = *p++;
    //3线
    p = (int*)&(pData->P3Angle);
    for(i = 0 ;i < 7; i++)
        PhasorArrow3P[i].Angle = *p++;
    //单线
    p = (int*)&(pData->P1Angle);
    for(i = 0 ;i < 2; i++)
        PhasorArrow1P[i].Angle = *p++;
}


/**********************************************************************************************************************
*   函数名: ModelReSize
*   建立者: 王昊
* 建立日期: 2009.02.18
* 修改日期: 2009.02.18
*     参数:
*           tb: PHASOR指针 指向需要处理的PHASOR结构数据
*   返回值: 无
* 功能介绍:
*           根据用户给定的背景半径调整箭头长度
*           >100 加长箭头 <100缩短箭头
**********************************************************************************************************************/

static  void    ModelReSize(PHASOR*	tb)
{
    int     i;
    float   rate;

    //半径/默认大小 100
    // rate = tb->Radius / DEFAULT_SIZE;
    rate = tb->Radius /75.0;
    for(i=0;i< 8;i++)
    {
        DeltaT[i].x = DeltaT[i].x * rate;
        DeltaT[i].y = DeltaT[i].y * rate;
    }
}


/**********************************************************************************************************************
*   函数名: GetRadian
*   建立者: 王昊
* 建立日期: 2008.08.14
* 修改日期: 2008.08.14
*     参数:
*           angel:角度值
*   返回值: 弧度值
* 功能介绍:
*           把角度变弧度
**********************************************************************************************************************/

static  float	GetRadian(float	angel)
{
    return	angel * (3.14159265358979F / 180.0F);
}
 /**********************************************************************************************************************
 *   函数名: RotateVertex
 *   建立者: 王昊
 * 建立日期: 2009.02.26
 * 修改日期: 2009.02.26
 *     参数: vp      :顶点
 *     参数: angel   :角度
 *   返回值: 无
 * 功能介绍:
 *           旋转一个顶点
 **********************************************************************************************************************/

void    RotateVertex(GUI_POINT* vp,float   angel)
{
    float   r = GetRadian(angel);
    float   x,y;
    float   tx = vp->x;
    r *=-1.0;
    x = (float)vp->x * cos(r);
    y = (float)vp->y * sin(r);
    tx = x + y;
    //vp->x = x + y;


    x = (float)-vp->x * sin(r);
    y = (float)vp->y * cos(r);
    vp->y = x + y;
    vp->x = tx;
}

/*********************************************************************************************************
画圆并用背景填充
参数：背景色，线条颜色，圆心、半径
*********************************************************************************************************/
void DrawCircle(QPainter *painter,QColor bkColor,QColor lineColor,int x,int y,int r)
{
    painter->setBrush(bkColor);
    painter->setPen(lineColor);
    painter->drawEllipse(x - r,y - r,r*2,r*2);
}
/*********************************************************************************************************
画矩形并用背景填充
参数：背景色，线条颜色，左上角、右下角的坐标
*********************************************************************************************************/
void DrawRectangle(QPainter *painter,QColor bkColor,QColor lineColor,int x,int y,int right,int bottom)
{
    painter->setBrush(QBrush(bkColor));
    painter->setPen(lineColor);
    painter->drawRect(x,y,right-x,bottom-y);
}
/*********************************************************************************************************
画线
参数：线条颜色，线条样式，起点、终点的坐标
*********************************************************************************************************/
void DrawLine(QPainter *painter,QColor lineColor,Qt::PenStyle style,int x,int y,int right,int bottom)
{
    QPen pen;
    pen.setColor(lineColor);
    pen.setStyle(style);
    painter->setPen(pen);

    painter->drawLine(x,y,right,bottom);
}

/*********************************************************************************************************
画相量的箭头
参数：线条颜色，相量，箭头原形
*********************************************************************************************************/
void DrawArrow(QPainter *painter,PHASOR*	tb,PHASOR_ARROW *arrow,bool isFill)
{
    //旋转箭头
    for(int i=0;i<8;i++)
    {
        DeltaT[i]=arrow->pModel[i];
        RotateVertex(&DeltaT[i],arrow->Angle);
    }
    //重新调整箭头长短
    ModelReSize(tb);
    //偏移到合适位置
    for(int i=0;i<8;i++)
    {
        DeltaT[i].x +=tb->PosX;
        DeltaT[i].y +=tb->PosY;
    }
    //绘制箭头
    painter->setPen(arrow->Color);

    if(isFill)
        painter->setBrush(arrow->Color);
    else
        painter->setBrush(QBrush(tb->BkColor));

    QPoint points[8];
    for(int i=0;i<8;i++)
    {
        points[i].setX(DeltaT[i].x);
        points[i].setY(DeltaT[i].y);
    }
    painter->drawPolygon(points,8);

    //输出文字
    int xhint = 5; //补偿
    int yhint = 0;

    painter->drawText(xhint  + DeltaT[4].x,yhint  + DeltaT[4].y,	arrow->Text);
}

/**********************************************************************************************************************
*   函数名: PhasorDraw
*   建立者: 王昊
* 建立日期: 2009.02.18
*   修改者: 荣斐飞
* 修改日期: 2009.10.23
*     参数:
*           pData: void指针  需要强行转换为PHASOR指针
*   返回值: 无
* 功能介绍:
*           绘制PHASOR
**********************************************************************************************************************/

void PhasorDraw(PHASOR*	pData,QPainter *painter)
{
    PHASOR*	tb = (PHASOR*)pData;
    //float	radian;
    int     i;
    int     length[]={0,2,0,7,6}; // 单相 1 = 2箭头 3线 3 = 7箭头 4线 4=6箭头
    //int     xhint,yhint;

    //读取角度
    GetAngle(tb);


    //选择背景样式 圆或者方
    if(tb->Background)
    {
        //设置背景颜色
        DrawRectangle(painter,WHITE,WHITE,tb->PosX - tb->Radius,tb->PosY - tb->Radius,
            tb->PosX + tb->Radius,tb->PosY + tb->Radius);

        //绘制边框
        DrawCircle(painter,tb->BkColor,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius);
    }
    else
    {
        //背景
        DrawCircle(painter,WHITE,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius+15);
        DrawCircle(painter,tb->BkColor,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius);
        DrawCircle(painter,tb->BkColor,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius *3/4);
        DrawCircle(painter,tb->BkColor,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius /2);
        DrawCircle(painter,tb->BkColor,tb->FrameColor,tb->PosX,tb->PosY,tb->Radius /4);

        //绘制斜线
        //左上30斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX-cos(30*3.14/180.0)*tb->Radius,tb->PosY-sin(30*3.14/180.0)*tb->Radius);
        //左上60斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX-cos(60*3.14/180.0)*tb->Radius,tb->PosY-sin(60*3.14/180.0)*tb->Radius);
        //右下30斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX +cos(30*3.14/180.0)*tb->Radius,tb->PosY +sin(30*3.14/180.0)*tb->Radius);
        //右下60斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX +cos(60*3.14/180.0)*tb->Radius,tb->PosY + sin(60*3.14/180.0)*tb->Radius);
        //左下30斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX-cos(30*3.14/180.0)*tb->Radius,tb->PosY+sin(30*3.14/180.0)*tb->Radius);
        //左下60斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX-cos(60*3.14/180.0)*tb->Radius,tb->PosY+sin(60*3.14/180.0)*tb->Radius);
        //右上30斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX +cos(30*3.14/180.0)*tb->Radius,tb->PosY -sin(30*3.14/180.0)*tb->Radius);
        //右上60斜线
        DrawLine(painter,tb->FrameColor,LINE_DOT,tb->PosX,tb->PosY,
            tb->PosX +cos(60*3.14/180.0)*tb->Radius,tb->PosY - sin(60*3.14/180.0)*tb->Radius);

        //横线
        DrawLine(painter,tb->FrameColor,LINE_SOLID,tb->PosX - tb->Radius,tb->PosY ,tb->PosX,tb->PosY);
        DrawLine(painter,tb->FrameColor,LINE_SOLID,tb->PosX  ,tb->PosY ,tb->PosX + tb->Radius,tb->PosY);
        //竖线
        DrawLine(painter,tb->FrameColor,LINE_SOLID,tb->PosX,tb->PosY - tb->Radius,tb->PosX,tb->PosY );
        DrawLine(painter,tb->FrameColor,LINE_SOLID,tb->PosX,tb->PosY ,tb->PosX,tb->PosY + tb->Radius);
        
        painter->drawText(tb->PosX,tb->PosY - tb->Radius,"0");
        painter->drawText(tb->PosX + tb->Radius,tb->PosY,"90");
        painter->drawText(tb->PosX-10,tb->PosY + tb->Radius+10,"180");
        painter->drawText(tb->PosX - tb->Radius-15,tb->PosY,"270");
    }

    if(tb->Connect<=0) //没有数据，无需画图
        return;

    //绘制箭头
    for(i = 0 ;i < length[tb->Connect] ; i++)
    {
        if(PhasorArrowSet[tb->Connect][i].Visiable != 0)
            continue;

        //绘制箭头
        if(i<=2)
            DrawArrow(painter,tb,&PhasorArrowSet[tb->Connect][i],true);
        else
            DrawArrow(painter,tb,&PhasorArrowSet[tb->Connect][i],false);

    }
}

/**********************************************************************************************************************
*   函数名: setData
*   修改者: 荣斐飞
* 建立日期: 2009.12.25
* 修改日期: 2009.12.25
*     参数:
*           无
*   返回值: 需要显示到左侧的字符串
* 功能介绍: 计算相量角度（4线）
**********************************************************************************************************************/

QString GraphPhasor::setData(int jxfs,double UaIa,double UaIb,double UaIc,double UaUb,double UaUc,double UbIb,double UcIc)
{
    static  int  Ua = 0;
    static  int  Ub = 0;
    static  int  Uc = 0;
    static  int  Ia = 0;
    static  int  Ib = 0;
    static  int  Ic = 0;
    static  int  Uab = 0;
    static  int  Ucb = 0;
    QString str="";
    PHASOR  *obj=&phasor;
    if(jxfs==4)
    {
        obj->Connect= P3L4;

        Ua = 0;
        Ub = UaUb - Ua;
        Uc = UaUc - Ua;
        Ia = UaIa - Ua;
        Ib = UaIb - Ua;
        Ic = UaIc - Ua;

        obj->P4Angle.Ua=Ua;
        obj->P4Angle.Ub=Ub;
        obj->P4Angle.Uc=Uc;
        obj->P4Angle.Ia=Ia;
        obj->P4Angle.Ib=Ib;
        obj->P4Angle.Ic=Ic;

        str.sprintf("φUaUb=%.1f°\r\n\r\nφUaUc=%.1f°\r\n\r\nφUaIa=%.1f°\r\n\r\nφUbIb=%.1f°\r\n\r\nφUcIc=%.1f°",
                    UaUb,UaUc,UaIa,UbIb,UcIc);
    }
    else if(jxfs==3)
    {
        obj->Connect= P3L3;

        Ua = 0;
        Ub = 120;
        Uc = 240;
        Uab = 270 - UaUc;
        Ucb = UaUc + Uab ;
        Ia = Uab + UaIa;
        Ic = Ucb + UcIc;

        obj->P3Angle.Ua=Ua;
        obj->P3Angle.Ub=Ub;
        obj->P3Angle.Uc=Uc;
        obj->P3Angle.Ia=Ia;
        obj->P3Angle.Uab=Uab;
        obj->P3Angle.Ic=Ic;
        obj->P3Angle.Ucb=Ucb;

        str.sprintf("φUabUcb=%.1f°\r\n\r\nφUabIa=%.1f°\r\n\r\nUcbIc=%.1f°",
                    UaUb,UaIa,UcIc);
    }
    else
    {
        obj->Connect= P1L1;

        Ua = 0;
        Ub = 120;
        Uc = 240;
        Uab = UaUc - 270;
        Ucb = - ( UaUc - Uab );
        Ia = Uab - UaIa;
        Ic = 360 + (Ucb - UcIc);

        obj->P1Angle.Ua=Ua;
        obj->P1Angle.Ia=Ia;
    }

    update();
    return str;
}
